package com.liuyu.common.framework.common.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

/**
 * @author LiuYu
 * @Project:eplatform
 * @Title:验证工具类
 * @Description:主要提供接口的验证规则
 * @date 2019/6/27 9:04
 * @Copyright:liuyu
 * @version:V1.0
 */

@Slf4j
public class ValidUtils {

    private static final String SECOND_PARRENT = "00";

    /**
     * 获取起保时间的最低时间限制
     *
     * @param day
     * @return
     */
    private static Calendar getStartDateLimit(int hour, int day) {
        Calendar calendar = Calendar.getInstance();
        if (day > 0) {
            calendar.set(Calendar.HOUR_OF_DAY, 0);
        }
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.HOUR_OF_DAY, hour);
        calendar.add(Calendar.DAY_OF_MONTH, day);
        return calendar;
    }


    /**
     * 字符串转化成日期格式
     *
     * @param date
     * @param hour
     * @return
     * @throws ParseException
     */
    public static Calendar getDate(String date, int hour) throws ParseException {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Date d = df.parse(date);
        calendar.setTime(d);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.HOUR_OF_DAY, hour);
        return calendar;
    }

    /**
     * 判断起保时间是否符合规定范围
     *
     * @param startDate
     * @param hour
     * @param delayDay
     * @param delayHour
     * @param isNotZeroHour 是否允许非零点起保 true  ,false 为不允许
     * @return
     */
    public static ValidResponse validStartDate(String startDate, int hour, int delayDay, int delayHour, boolean isNotZeroHour) {
        //当不允许非零起保时间时，如果使用非零则返回。
        if (!isNotZeroHour && hour != 0) {
            return new ValidResponse(false, "起保小时不允许非零！");
        }
        Calendar startDateLimit = getStartDateLimit(delayHour, delayDay);
        Calendar startDate1;
        try {
            startDate1 = getDate(startDate, hour);
        } catch (ParseException e) {
            log.error(e.getMessage(), e);
            return new ValidResponse(false, "起保日期格式错误");
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info("起保日期限制：{},起保时间：{}，起保日期必须>=起保日期限制", dateFormat.format(startDateLimit.getTime()), dateFormat.format(startDate1.getTime()));
        if (startDate1.before(startDateLimit)) {
            int day = calcDayOffset(startDate1, startDateLimit);
            return new ValidResponse(false, "起保日期和起保小时早于约定的最早起保时间", day);
        }
        return new ValidResponse(true, "校验成功");
    }


    /**
     * 判断起保时间是否符合规定范围
     *
     * @param startDate
     * @param hour
     * @param minuteAndSecond 格式："MM:ss"
     * @param delayDay
     * @param delayHour
     * @param isNotZeroHour   是否允许非零点起保 true  ,false 为不允许
     * @return
     */
    public static ValidResponse validStartDateTime(String startDate, int hour, String minuteAndSecond, int delayDay, int delayHour, int delayMinute, boolean isNotZeroHour) {
        //当不允许非零起保时间时，如果使用非零则返回。
        if (!isNotZeroHour && hour != 0) {
            return new ValidResponse(false, "起保小时不允许非零！");
        }
        int delayMinutes;
        if (delayDay == 0 && delayHour == 0) {
//            由于请求时间差导致的问题
            delayMinutes = (delayMinute - 5) < 0 ? 0 : delayMinute - 5;
        } else {
            delayMinutes = delayMinute;
        }
        //获取最后的限额
        LocalDateTime startDateLimit = LocalDateTime.now().plusDays(delayDay).plusHours(delayHour).plusMinutes(delayMinutes).withSecond(0);
        LocalDateTime startDateTime;
        try {
            startDateTime = getLocalDateTime(startDate, hour, minuteAndSecond, false);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return new ValidResponse(false, "起保时间日期格式错误");
        }
        log.info("起保时间限制：{},起保时间：{}，起保时间必须>=起保时间限制", startDateLimit, startDateTime);
        if (startDateTime.isBefore(startDateLimit)) {
            return new ValidResponse(false, "起保日期和起保小时早于约定的最早起保时间,最早时间:" + startDateLimit, startDateLimit);
        }
        return new ValidResponse(true, "校验成功");
    }


    public static LocalDateTime getLocalDateTime(String date, int hour, String minuteAndSecond, boolean isEndDate) throws Exception {
        String ms;
        boolean isSubOneSecond = false;
        if (StringUtils.isBlank(minuteAndSecond)) {
            ms = "00:00";
            isSubOneSecond = true;
        } else {
            ms = minuteAndSecond;
            if (minuteAndSecond.endsWith(SECOND_PARRENT)) {
                isSubOneSecond = true;
            }
        }
//        String datetime = date + "T" + (hour < 10 ? "0" + hour : hour) + ":" + ms+"+01:00";
        String datetime = date + " " + (hour < 10 ? "0" + hour : hour) + ":" + ms;
        LocalDateTime startDateTime;
        try {
            if (isEndDate) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                if (isSubOneSecond) {
//                    startDateTime = LocalDateTime.parse(datetime, df).plusSeconds(-1L);
                    Date d = dateFormat.parse(datetime);
//                    startDateTime = LocalDateTime.parse(datetime, df).plusSeconds(-1L);
                    startDateTime = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().plusSeconds(-1L);
                } else {
//                    startDateTime = LocalDateTime.parse(datetime, df);
                    Date d = dateFormat.parse(datetime);
//                    startDateTime = LocalDateTime.parse(datetime, df).plusSeconds(-1L);
                    startDateTime = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                }
            } else {
//                startDateTime = LocalDateTime.parse(datetime, df).plusSeconds(1L);
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                startDateTime = LocalDateTime.parse(datetime, df);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception("起保日期格式错误");
        }
        return startDateTime;
    }

    /**
     * 判断起保时间
     *
     * @param startDate 起保日期
     * @param startHour 起保小时
     * @param endDate   终报日期
     * @param endHour   终报小时
     * @param year      允许相差年
     * @param month     允许相差月份
     * @param day       允许相差天
     * @return
     */
    public static ValidResponse validEndDateTime(String startDate, int startHour, String startMinuteAndSecond, String endDate, int endHour, String endMinuteAndSecond, int year, int month, int day, int hour, int minute) {
        LocalDateTime endDateTimeLimit;
        LocalDateTime endDateTime;
        try {
            endDateTimeLimit = getLocalDateTime(startDate, startHour, startMinuteAndSecond, true).plusYears(year).plusMonths(month).plusDays(day).plusHours(hour).plusMinutes(minute);
            endDateTime = getLocalDateTime(endDate, endHour, endMinuteAndSecond, true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return new ValidResponse(false, "终保时间日期格式错误");
        }


        log.info("终保时间限定:{},终保时间：{},终保时间必须等于终保时间限定", endDateTimeLimit, endDateTime);
        //如果不相等则返回失败
        if (endDateTime.isEqual(endDateTimeLimit)) {
            return new ValidResponse(true, "终保日期时间符合规定");
        }
        return new ValidResponse(false, "终保日期时间不符合,正确时间:" + endDateTimeLimit);
    }


    /**
     * 判断起保时间
     *
     * @param startDate 起保日期
     * @param startHour 起保小时
     * @param endDate   终报日期
     * @param endHour   终报小时
     * @param year      允许相差年
     * @param month     允许相差月份
     * @param day       允许相差天
     * @return
     */
    public static ValidResponse validEndDate(String startDate, int startHour, String endDate, int endHour, int year, int month, int day) {
        Calendar endDateLimit = null;
        try {
            endDateLimit = getDate(startDate, startHour);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        endDateLimit.add(Calendar.YEAR, year);
        endDateLimit.add(Calendar.MONTH, month);
        endDateLimit.add(Calendar.DAY_OF_MONTH, day);
        Calendar calendar = null;
        try {
            calendar = getDate(endDate, endHour);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //如果不相等则返回失败
        log.info("终保日期限定:{},终保日期：{},终保日期必须等于终保时间限定", dateFormat.format(endDateLimit.getTime()), dateFormat.format(calendar.getTime()));
        if (calendar.compareTo(endDateLimit) != 0) {
            return new ValidResponse(false, "终保日期不符合");
        }
        return new ValidResponse(true, "终保时间符合规定");
    }


    /**
     * http://www.cnblogs.com/0201zcr/p/5000977.html
     * date2比date1多的天数
     *
     * @param cal1
     * @param cal2
     * @return
     */
    public static int calcDayOffset(Calendar cal1, Calendar cal2) {
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);
        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        //同一年
        if (year1 != year2) {
            int timeDistance = 0;
            for (int i = year1; i < year2; i++) {
                //闰年
                boolean result = i % 4 == 0 && i % 100 != 0 || i % 400 == 0;
                if (result) {
                    timeDistance += 366;
                    //不是闰年
                } else {
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2 - day1);
            //不同年
        } else {
            return day2 - day1;
        }
    }

    /**
     * 清理时间校验信息
     *
     * @param errorList
     * @return void
     * @throws
     * @author liuyu
     * @date 2022/11/30 12:52
     */
    public static void cleanValidDate(List<String> errorList) {
        Iterator<String> it = errorList.iterator();
        while (it.hasNext()) {
            String obj = it.next();
            //清理时间上的
            if (obj.contains("起保") || obj.contains("终保")) {
                it.remove();
            }
        }
        removeNull(errorList);
    }


    @Data
    public static class ValidResponse<T> {
        private boolean result;
        private String code;
        private String message;
        private T data;

        public ValidResponse(boolean result, String message) {
            this.result = result;
            this.message = message;
        }

        public ValidResponse(boolean result, String code, String message) {
            this.result = result;
            this.code = code;
            this.message = message;
        }

        public ValidResponse(boolean result, String message, T data) {
            this.result = result;
            this.message = message;
            this.data = data;
        }
    }

    /**
     * 清理listnull
     *
     * @param list
     * @return void
     * @throws
     * @author liuyu
     * @date 2022/11/30 12:50
     */
    public static <T> void clearNull(List<T> list) {
        Collection nuCon = new Vector();
        nuCon.add((Object) null);
        list.removeAll(nuCon);
    }

    /**
     * 清理list null
     *
     * @param oldList
     * @return java.util.List<? extends T>
     * @throws
     * @author liuyu
     * @date 2022/11/30 12:50
     */
    public static <T> List<? extends T> removeNull(List<? extends T> oldList) {
        oldList.removeAll(Collections.singleton((Object) null));
        return oldList;
    }

}
